"""
  Copyright (c) 2024 Northeastern University (China)
  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
"""
import math
import multiprocessing
import os.path
import re
import subprocess
import traceback

import chardet
from bson import ObjectId
from tqdm import tqdm

from src.common_utils import configure
from src.operate_db.test.dependency_testcase import DependencyTestCase
from src.operate_db.test.dependency_indirect import Indirect
ctagsPath= configure.CONFIG['ctags_path']


def removeComment( string):
    # Code for removing C/C++ style comments. (Imported from VUDDY and ReDeBug.)
    # ref: https://github.com/squizz617/vuddy
    c_regex = re.compile(
        r'(?P<comment>//.*?$|[{}]+)|(?P<multilinecomment>/\*.*?\*/)|(?P<noncomment>\'(\\.|[^\\\'])*\'|"(\\.|[^\\"])*"|.[^/\'"]*)',
        re.DOTALL | re.MULTILINE)
    return ''.join([c.group('noncomment') for c in c_regex.finditer(string) if c.group('noncomment')])
def global_feature( module_dic, target_features, dependency_dic):
    """
    1.执行ctags命令，获得每个模块中定义了哪些全局变量和函数
    2.同时记录类对象，结构体对象，枚举类型的名称作为间接依赖的特征
    :param targetPath: 目标代码路径
    :return:
    """
    cnt = 0
    for moudle in module_dic:
        indiirect_dependency = []
        for filePath in moudle['path']:
            try:
                # Execute Ctgas command
                TagsList = subprocess.check_output(ctagsPath + ' -f - --kinds-C=* --fields=+KS "' + filePath + '"',
                                                   stderr=subprocess.STDOUT, shell=True).decode()
                allGlobals = str(TagsList).split('\n')
                for i in allGlobals:
                    if not i.startswith("!_TAG"):
                        feature = None  # 全局特征
                        dependency = None  # 依赖信息
                        statement = None  # 依赖语句
                        Identifier = None  # 标识符
                        elemList = re.sub(r'[\t\s ]{2,}', '', i)
                        elemList = elemList.split('\t')
                        print(elemList)
                        if i != '' and len(elemList) >= 4:
                            if re.compile(r'(variable)').fullmatch(elemList[3]):  # 标识符是变量定义
                                feature_reg = elemList[2]
                                pattern = r"\/\^\s*(friend|static)"
                                if re.match(pattern, feature_reg):
                                    pass
                                else:
                                    if elemList[4].startswith("typeref:typename:") and not feature_reg.startswith(
                                            '/^static'):  # 这是为了防止静态变量出现
                                        # print(elemList)
                                        feature = {
                                            'feature_type': 'variable',
                                            'name': elemList[0],
                                            'type': elemList[-1].replace("typeref:typename:", "").strip('\r'),
                                            'filepath': str(filePath)
                                        }

                            elif re.compile(r'(function)').fullmatch(elemList[3]):  # 标识符是函数定义
                                feature_reg = elemList[2]
                                pattern = r"\/\^\s*(friend|static)"
                                if re.match(pattern, feature_reg):
                                    pass
                                else:
                                    if elemList[4].startswith("typeref:typename:") and not feature_reg.startswith(
                                            '/^static'):  # 说明这个函数不是类得成员
                                        feature = {
                                            'feature_type': 'function',
                                            'name': elemList[0],
                                            'type': elemList[4].replace("typeref:typename:", ""),
                                            'signature': elemList[-1].replace("signature:", "").strip('\r'),
                                            'filepath': str(filePath)
                                        }

                            elif re.compile(r'(externvar)').fullmatch(elemList[3]):  # 标识符是外部变量extern
                                dependency = {
                                    'statement_type': 'variable',
                                    'name': elemList[0],
                                    'type': elemList[-1].replace("typeref:typename:", "").strip('\r'),
                                    'filepath': str(filePath)
                                }
                                statement = elemList[2].strip("{$/;")
                                statement = statement.strip("/^")
                            elif re.compile(r'(prototype)').fullmatch(elemList[3]):  # 标识符是函数的原型，有可能存在extern
                                if elemList[4].startswith("typeref:typename:") and "extern " in elemList[
                                    2]:  # 说明这个函数原型不是在类或者结构体中
                                    dependency = {
                                        'statement_type': 'function',
                                        'name': elemList[0],
                                        'type': elemList[4].replace("typeref:typename:", ""),
                                        'signature': elemList[-1].replace("signature:", "").strip('\r'),
                                        'filepath': str(filePath)
                                    }
                                    statement = elemList[2]
                            # 以下提取标识符
                            # 只提取类，结构体，枚举
                            elif re.compile(r'(class)').fullmatch(elemList[3]):  # 标识符是函数定义
                                feature_reg = elemList[2]
                                inner_id = False
                                namespace = ""
                                if not elemList[0].islower():
                                    for i in range(3, len(elemList)):
                                        if elemList[i].strip().startswith("namespace"):
                                            namespace = elemList[i].replace("namespace:",
                                                                            "").strip()  # 类似于：namespace:first_space::second_space
                                            break
                                        elif elemList[i].strip().startswith("struct:") or elemList[
                                            i].strip().startswith(
                                            "class:") or elemList[i].strip().startswith("enum:"):
                                            inner_id = True
                                            break
                                    if not inner_id:
                                        Identifier = {
                                            'feature_type': 'class',
                                            'name': elemList[0],
                                            'filepath': filePath,
                                            'namespace': namespace,
                                            'weight': 2
                                        }
                            elif re.compile(r'(struct)').fullmatch(elemList[3]):  # 标识符是函数定义
                                feature_reg = elemList[2]
                                inner_id = False
                                namespace = ""
                                if not elemList[0].islower():
                                    for i in range(3, len(elemList)):
                                        if elemList[i].strip().startswith("namespace"):
                                            namespace = elemList[i].replace("namespace:",
                                                                            "").strip()  # 类似于：namespace:first_space::second_space
                                            break
                                        elif elemList[i].strip().startswith("struct:") or elemList[
                                            i].strip().startswith("class:") or elemList[i].strip().startswith("enum:"):
                                            inner_id = True
                                            break
                                    if not inner_id:
                                        Identifier = {
                                            'feature_type': 'struct',
                                            'name': elemList[0],
                                            'filepath': filePath,
                                            'namespace': namespace,
                                            'weight': 2
                                        }
                            elif re.compile(r'(enum)').fullmatch(elemList[3]):  # 标识符是变量定义
                                feature_reg = elemList[2]
                                inner_id = False
                                namespace = ""
                                if not elemList[0].islower():
                                    for i in range(3, len(elemList)):
                                        if elemList[i].strip().startswith("namespace"):
                                            namespace = elemList[i].replace("namespace:",
                                                                            "").strip()  # 类似于：namespace:first_space::second_space
                                            break
                                        elif elemList[i].strip().startswith("struct:") or elemList[
                                            i].strip().startswith(
                                            "class:") or elemList[i].strip().startswith("enum:"):
                                            inner_id = True
                                            break
                                    if not inner_id:
                                        Identifier = {
                                            'feature_type': 'enum',
                                            'name': elemList[0],
                                            'filepath': filePath,
                                            'namespace': namespace,
                                            'weight': 2
                                        }
                            if feature is not None:
                                if feature in target_features[cnt]['global_feature']:
                                    pass
                                else:
                                    if feature['feature_type'] == 'variable':
                                        target_features[cnt]['global_var'].append(elemList[0])
                                    elif feature['feature_type'] == 'function':
                                        target_features[cnt]['global_func'].append(elemList[0])
                                    target_features[cnt]['global_feature'].append(feature)
                            if Identifier is not None:
                                target_features[cnt]['indirect_feature'].append(Identifier)
                                target_features[cnt]['indirect_feature'] = sorted(
                                    target_features[cnt]['indirect_feature'], key=lambda x: x['weight'],
                                    reverse=True)
                            if dependency is not None and dependency not in dependency_dic[cnt][
                                'orig_extern_dependency']:
                                dependency_dic[cnt]['orig_extern_dependency'].append(dependency)
                                dependency_dic[cnt]['orig_extern_dependency_statement'].append(statement)
            except subprocess.CalledProcessError as e:
                print("Parser Error:", e)
                traceback.print_exc()
                continue
            except Exception as e:
                print("Subprocess failed", e)
                traceback.print_exc()
                continue
        cnt = cnt + 1
    return target_features, dependency_dic
def is_short_path_contained_in_long_path(use_namespace, namespace):
    use_namespace_node = use_namespace.split("::")
    namespace_npde = namespace.split("::")
    # 从最后一个节点开始比较
    short_index = len(use_namespace_node) - 1
    long_index = len(namespace_npde) - 1

    while short_index >= 0 and long_index >= 0:
        if use_namespace_node[short_index] != namespace_npde[long_index]:
            # 如果节点不匹配，返回False
            return False
        short_index -= 1
        long_index -= 1

    return short_index < 0
def process_line(l,pattern,id,using_namespace,define_namespace):
    id_flag = False
    use_namespace=""
    words = l.split()  # 按照空格将代码拆分成分词
    for word in words:
        if re.search(pattern, word):  # 找到将要处理的代码分词
            matches = list(re.finditer(pattern, word))
            end=-1
            if matches:
                last_match = matches[-1]
                start = last_match.start()  # 最后一次匹配项的起始位置
                end = last_match.end()  # 最后一次匹配项的结束位置
                print(f"Last match found at position {start}-{end}: '{word[start:end]}'")
            else:
                print("No matches found.")
            if end != -1:
                print(f"之前word {word}")
                word = word[:end]
                print(f"word {word}")
            truth_namespace = id['namespace'].split("::")  # 这个标识符真实的最小命名空间
            if len(id['namespace']) == 0:  # 标识符是全局空间
                print("标识符是全局空间")
                id_flag = True
                break
            if "::"+id['name'] in word: # 如果类似 ::Want在代码中，表明存在空间限定
                print("命名空间完全限定")
                remove = ""
                for i in range(0, len(truth_namespace)):
                    namespace_limit_id = id['namespace'].replace(remove, "") + "::" + id['name']
                    print(namespace_limit_id)
                    print(word)
                    if namespace_limit_id in word:  # 说明完全限定的标识符存在
                        id_flag = True
                        use_namespace = id['namespace'].replace(remove, "")
                        break
                    remove = remove + truth_namespace[i] + "::"
            else:
                print("没有命名空间限定")
                print(f"从using 指令开始对比:{using_namespace}")
                for use_nsp in set(using_namespace):
                    if is_short_path_contained_in_long_path(use_nsp, id['namespace']):
                        id_flag = True
                        use_namespace = use_nsp
                print(f"从不连续命名空间对比:{define_namespace}")
                if not id_flag:#如果从using 指令没有找到命名空间
                    for use_nsp in set(define_namespace):
                        if "::" in use_nsp:# 嵌套命名空间形式 namespace first::second{},这种情况只需要保证标识符最小限定在命名空间限定词中即可
                            if id['namespace'].split("::")[-1] in use_nsp:
                                id_flag = True
                                use_namespace = use_nsp
                        if is_short_path_contained_in_long_path(use_nsp, id['namespace']):
                            id_flag = True
                            use_namespace = use_nsp

    return id_flag,use_namespace
def is_unquoted_string(s,target_string):
    # 使用正则表达式来匹配不包含在双引号中的字符串
    pattern =fr'".*{target_string}.*"'
    match = re.search(pattern, s)
    if match:
       return False
    else:
        return True
def split_list( list, n):
    """
    将数据n等分，分发给n个线程执行

    :param list: 原始完整list
    :param n: 切分数量，即线程数量
    :return: 切分后的list起始位置
    """
    step_count = math.ceil(len(list) / n)
    for i in range(0, len(list), step_count):
        end = i + step_count
        if end > len(list):
            end = len(list)
        # print(f"yield: {i}:{end}")
        yield list[i:end]
def checking_Identifier_in_source_main(filepaths,Identifier,target_path,numprocess):
    manager = multiprocessing.Manager()
    dependency = manager.list()
    appear = manager.list()
    dependency_type = manager.list()
    id_flag = manager.Value("b",False)  # 表示是否找到标识符
    lock=manager.Lock()
    with multiprocessing.Pool(processes=numprocess) as pool:
        # 将任务分配给进程池
        pool.map(checking_Identifier_in_source_detail,
                 [(idx + 1, list_arr, Identifier,target_path,dependency,appear,dependency_type,id_flag,lock) for
                  idx, list_arr in enumerate(split_list(filepaths, numprocess))])
    return list(dependency), list(dependency_type), list(appear)
def checking_Identifier_in_source_detail(args):
    idx, listarr, Identifier,target_path,dependency,appear,dependency_type,id_flag,lock=args
    for path in tqdm(listarr,total=len(listarr),desc=f'{idx}处理间接依赖进度：'):
        filepath=os.path.join(target_path,path.strip("\\"))
        with lock:
            if id_flag.value:
                break
            else:
                try:
                    with open(filepath, 'rb') as f:
                        result = chardet.detect(f.read())  # 检测文件编码
                    encoding = result['encoding']
                    with open(filepath, 'r', encoding=encoding) as f:
                        using_namespace=[] #先预设命名空间是全局，这是使用using指令
                        define_namespace=[] #这是不连续命名空间
                        content = f.read()
                        lines=removeComment(content)
                        lines=lines.split("\n")
                        for l in lines:
                            try:
                                if len(l)==0:#空行
                                    continue
                                l=removeComment(l)
                                l=l.strip()#去除头尾各种特殊符号和空格
                                using_pattern = r'^using\s+namespace\s+(.*);'
                                using_match = re.match(using_pattern, l)
                                if using_match:
                                    using_namespace.append(using_match.group(1).strip())
                                    continue
                                namespace_pattern = r'namespace\s+([\w:]+)\s*{'
                                namespace_match = re.search(namespace_pattern, l)
                                if namespace_match:
                                    define_namespace.append(namespace_match.group(1).strip())
                                    continue
                                for id in Identifier:
                                    # 使用正则表达式查找
                                    pattern = r'\b{}\b'.format(re.escape(id['name']))
                                    if re.search(pattern, l) and is_unquoted_string(l,id['name']):#防止标识符出现在双引号中也就是输出中，所有这行代码没有双引号才做判断
                                        print(f"{l}出现标识符{id['name']}")
                                        appear.append(id['name'])
                                        id_flag.value,use_namespace=process_line(l,pattern,id,using_namespace,define_namespace)
                                        print(f'看：{id_flag},{id_flag.value}')
                                        if id_flag.value:
                                            dep = {
                                                'dependency': {
                                                    'statement': l,
                                                    'filepath': path,
                                                    'namespace': use_namespace
                                                },
                                                'dependency_type': 'indirect',
                                                'dependency_id': id
                                            }
                                            if dep not in dependency:
                                                dependency.append(dep)
                                            if id['feature_type'] not in dependency_type:
                                                dependency_type.append(id['feature_type'])
                                            break
                                if id_flag.value:
                                    break
                            except Exception as e:
                                traceback.print_exc()
                                print(f"error: {str(e)}")
                                continue
                except Exception as e:
                    traceback.print_exc()
                    print(f"error: {str(e)}")
                    continue


def checking_Identifier_in_source(filepaths,Identifier,target_path):
    """
    识别间接依赖的核心函数
    检测思路：
    扫描Afile中是不是存在Bfile的标识符
    @param filepaths: 需要扫描的源码文件
    @param Identifier: 需要对比的标识符集合
    @return:
    """
    dependency=[]
    appear=[]
    dependency_type=[]
    id_flag=False   #表示是否找到标识符
    for path in filepaths:
        filepath=os.path.join(target_path,path)
        try:
            with open(filepath, 'rb') as f:
                result = chardet.detect(f.read())  # 检测文件编码
            encoding = result['encoding']
            with open(filepath, 'r', encoding=encoding) as f:
                using_namespace=[] #先预设命名空间是全局，这是使用using指令
                define_namespace=[] #这是不连续命名空间
                content = f.read()
                lines=removeComment(content)
                lines=lines.split("\n")
                for l in lines:
                    try:
                        if len(l)==0:#空行
                            continue
                        l=removeComment(l)
                        l=l.strip()#去除头尾各种特殊符号和空格
                        using_pattern = r'^using\s+namespace\s+(.*);'
                        using_match = re.match(using_pattern, l)
                        if using_match:
                            using_namespace.append(using_match.group(1).strip())
                            continue
                        namespace_pattern = r'namespace\s+([\w:]+)\s*{'
                        namespace_match = re.search(namespace_pattern, l)
                        if namespace_match:
                            define_namespace.append(namespace_match.group(1).strip())
                            continue
                        for id in Identifier:
                            # 使用正则表达式查找
                            pattern = r'\b{}\b'.format(re.escape(id['name']))
                            if re.search(pattern, l) and is_unquoted_string(l,id['name']):#防止标识符出现在双引号中也就是输出中，所有这行代码没有双引号才做判断
                                print(f"{l}出现标识符{id['name']}")
                                appear.append(id['name'])
                                id_flag,use_namespace=process_line(l,pattern,id,using_namespace,define_namespace)
                                if id_flag:
                                    break
                            else:
                                print("没有出现标识符")
                        if id_flag:
                            dep={
                                'dependency':{
                                    'statement':l,
                                    'filepath': path,
                                    'namespace': use_namespace
                                },
                                'dependency_type':'indirect',
                                'dependency_id':id
                            }
                            if dep not in dependency:
                                dependency.append(dep)
                            if id['feature_type'] not in dependency_type:
                                dependency_type.append(id['feature_type'])
                            break
                    except Exception as e:
                        traceback.print_exc()
                        print(f"error: {str(e)}")
                        continue
        except Exception as e:
            traceback.print_exc()
            print(f"error: {str(e)}")
            continue
        if id_flag:
            break
    return dependency,dependency_type,appear
def batch_testing():
    indirect = Indirect()
    res = indirect.get({'success':0}, {})
    oss_dependency = {
        'name': 'test',
        'orig_include_dependency': [],
        'orig_extern_dependency': [],
        'orig_include_dependency_statement': [],
        'orig_extern_dependency_statement': [],
        'include_dependency': [],
        'extern_dependency': [],
    }
    dependency_dic = []
    dependency_dic.append(oss_dependency)
    for data in tqdm(res, total=len(res), desc="处理进度："):
        inputpath = data['A']
        targetpath = data['B']
        module_dic = [
            {
                'name': "a",
                'path': [inputpath]}
        ]
        oss_feature = {'name': 'a', 'head_file_feature': [], 'global_feature': [], 'indirect_feature': [],
                       'global_var': [], 'global_func': []}
        oss_dependency = {
            'name': 'a',
            'orig_include_dependency': [],
            'orig_extern_dependency': [],
            'orig_include_dependency_statement': [],
            'orig_extern_dependency_statement': [],
            'include_dependency': [],
            'extern_dependency': [],
        }
        target_features = []
        target_features.append(oss_feature)
        target_features, dependency_dic = global_feature(module_dic, target_features, dependency_dic)
        filepaths = [targetpath]
        success, type = checking_Identifier_in_source(filepaths, target_features[0]['indirect_feature'])
        indirect.update_one_with_id(data['_id'],
                                    {
                                        'verify': success[0] if len(success) != 0 else None,
                                        'type': type[0] if len(type) != 0 else None
                                    })
        truth = data['truth']
        if truth['contain']['feature_type'] == 'macro':  # 因为不考虑宏，所以如果truth是宏的时候我们没有检测出来是正确的
            if len(type) == 0:
                indirect.update_one_with_id(data['_id'], {'success': 1})
        else:
            if len(success) == 0:
                indirect.update_one_with_id(data['_id'], {'success': 0})
            else:
                if truth['contain']['name'].strip() == success[0]['contain']['name'].strip():
                    indirect.update_one_with_id(data['_id'], {'success': 1})
                else:
                    indirect.update_one_with_id(data['_id'], {'success': 0})
def batch_testing_AB():
    indirect = Indirect()
    res = indirect.get({'_id':ObjectId("653d05873631887a01612151")}, {})
    oss_dependency = {
        'name': 'test',
        'orig_include_dependency': [],
        'orig_extern_dependency': [],
        'orig_include_dependency_statement': [],
        'orig_extern_dependency_statement': [],
        'include_dependency': [],
        'extern_dependency': [],
    }
    dependency_dic = []
    dependency_dic.append(oss_dependency)
    for data in tqdm(res, total=len(res), desc="处理进度："):
        inputpath = data['A']
        targetpath = data['B']
        module_dic = [
            {
                'name': "a",
                'path': [inputpath]}
        ]
        oss_feature = {'name': 'a', 'head_file_feature': [], 'global_feature': [], 'indirect_feature': [],
                       'global_var': [], 'global_func': []}
        oss_dependency = {
            'name': 'a',
            'orig_include_dependency': [],
            'orig_extern_dependency': [],
            'orig_include_dependency_statement': [],
            'orig_extern_dependency_statement': [],
            'include_dependency': [],
            'extern_dependency': [],
        }
        target_features = []
        target_features.append(oss_feature)
        target_features, dependency_dic = global_feature(module_dic, target_features, dependency_dic)
        if len(target_features[0]['indirect_feature']) == 0:
            print("没有哦特征")
            indirect.update_one_with_id(data['_id'], {'success': 1,'detail':'A没有标识符特征'})
            continue
        filepaths = [targetpath]
        success, type,appear = checking_Identifier_in_source(filepaths, target_features[0]['indirect_feature'])
        indirect.update_one_with_id(data['_id'],
                                    {
                                        'verify': success[0] if len(success) != 0 else None,
                                        'type': type[0] if len(type) != 0 else None,
                                        'indirect_feature' :target_features[0]['indirect_feature']
                                    })

        if len(success) == 0 and len(appear)!=0:
            print(00)
            indirect.update_one_with_id(data['_id'], {'success': 0,'appear':list(set(appear))})
        else:
            if len(appear) == 0:
                indirect.update_one_with_id(data['_id'], {'success': 1, 'detail': 'B中没有出现A的标识符'})
            else:
                indirect.update_one_with_id(data['_id'], {'success': 1})
def construct_dependency_case():
    all=[]
    dependencyTestCase=DependencyTestCase()
    indirect = Indirect()
    res=dependencyTestCase.get({'new_graphy': []}, {'_id': 1,'verify_dep_either_namespace':1})
    for data in tqdm(res,total=len(res),desc=f"处理进度:"):

        if 'verify_dep_either_namespace' in data and data['verify_dep_either_namespace'] is not None:
            verify_dep_either_namespace=data['verify_dep_either_namespace']
            for verify in verify_dep_either_namespace:
                A=verify['contain']['filepath']
                B=verify['filepath']
                if (A,B) not in all:
                    all.append((A,B))
                    truth=verify
                    indirect.add_data({'A':A,
                                       'B':B,
                                       'truth':truth})
def construct_dependency_case_AB():
    all=[]
    dependencyTestCase=DependencyTestCase()
    indirect = Indirect()
    res=dependencyTestCase.get({'new_graphy': [ [ "A", "B" ] ]}, {'_id': 1,'new_dependency':1})
    for data in tqdm(res,total=len(res),desc=f"处理进度:"):

        if 'new_dependency' in data and data['new_dependency'] is not None:
            Adeps=data['new_dependency'][0]['final_dep']
            if len(Adeps)>1:
                print("超过1个deps")
            for dep in Adeps:
                source=dep['dependency']['filepath']
                target=dep['dependency_file'][0]
                if (source,target) not in all:
                    all.append((source,target))
                    truth="BA"
                    indirect.add_data({'A':target,
                                       'B':source,
                                       'truth':truth})


if __name__ == "__main__":
    #construct_dependency_case_AB()
    batch_testing_AB()
    # oss_dependency = {
    #     'name': 'test',
    #     'orig_include_dependency': [],
    #     'orig_extern_dependency': [],
    #     'orig_include_dependency_statement': [],
    #     'orig_extern_dependency_statement': [],
    #     'include_dependency': [],
    #     'extern_dependency': [],
    # }
    # dependency_dic = []
    # dependency_dic.append(oss_dependency)
    # inputpath = r"D:\wsj\open-harmony\harmony_source_repos\communication_bluetooth\frameworks\inner\ipc\common\gatt_data.h"
    # targetpath= r"D:\wsj\open-harmony\harmony_source_repos\communication_bluetooth\frameworks\inner\src\bluetooth_gatt_client.cpp"
    # module_dic = [
    #     {
    #         'name': "a",
    #         'path': [targetpath]}
    # ]
    # oss_feature = {'name': 'a', 'head_file_feature': [], 'global_feature': [], 'indirect_feature': [],
    #                'global_var': [], 'global_func': []}
    # oss_dependency = {
    #     'name': 'a',
    #     'orig_include_dependency': [],
    #     'orig_extern_dependency': [],
    #     'orig_include_dependency_statement': [],
    #     'orig_extern_dependency_statement': [],
    #     'include_dependency': [],
    #     'extern_dependency': [],
    # }
    # target_features = []
    # target_features.append(oss_feature)
    # target_features, dependency_dic = global_feature(module_dic, target_features, dependency_dic)
    # print(target_features)
    # filepaths = [targetpath]
    # success, type ,appear= checking_Identifier_in_source(filepaths, target_features[0]['indirect_feature'])
    # print(success)
    # print(type)